package com.gwtent.serialization.client.json;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.json.client.JSONException;

public class DateParser {
	private static List<DateTimeFormat> formatters = new ArrayList<DateTimeFormat>();
	private static boolean initialized = false;

	public static Date parse(String date) {
		if (!initialized) {
			initialize();
		}

		// Custom parsers
		for (DateTimeFormat formatter : formatters) {
			try {
				return formatter.parse(date);
			} catch (Exception e) {
				continue;
			}
		}

		try {
			// JS parser in browser
			return new Date(Long.parseLong(webDateToMilliSec(date)));
		} catch (Exception e) {

		}
		
		try {
			// Date class parser
			return new Date(date);
		} catch (Exception e) {

		}

		try {
			// UNIX timestamp
			return new Date(Long.parseLong(date));
		} catch (Exception e) {

		}

		throw new JSONException("Unable to parse date string: " + date);
	}

	private static void initialize() {
		// ISO 8601
		addFormats("yyyy-MM-dd'T'HH:mm", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ss:SSS", "yyyyMMdd", "yyyy-MM-dd", "yyyy-MM","yyyy");
		// ISO 8601 with space as delimiter
		addFormats("yyyy-MM-dd HH:mm", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss:SSS");
		// RFC822/1233 with weekdays (without military time zone format)
		addFormats("EEE, dd MMM yyyy HH:mm:ss zzz", "EEE, dd MMM yyyy HH:mm:ss Z");
		// RFC822/1233 without weekdays (without military time zone format)
		addFormats("dd MMM yyyy HH:mm:ss zzz", "dd MMM yyyy HH:mm:ss Z");
		// RFC 850/1036
		addFormats("EEEE, dd-MMM-yy HH:mm:ss zzz");
		// others
		addFormats("yyyy.MM.dd.", "yyyy.MM.dd. HH:mm", "dd/MM/yyyy");

		initialized = true;
	}

	private static void addFormats(String... formats) {
		for (String format : formats) {
			formatters.add(DateTimeFormat.getFormat(format));
		}
	}

	private static native String webDateToMilliSec(String webDate)
	/*-{
	var longDate = Date.parse(webDate);
	return longDate.toString();
	}-*/;
}
